#ifndef __yltkEventObject_h
#define __yltkEventObject_h

#include "yltkIndent.h"

namespace yltk{
	/** \class EventObject
	* \brief Abstraction of the Events used to communicating among filters
	and with GUIs.
	*
	* EventObject provides a standard coding for sending and receiving messages
	* indicating things like the initiation of processes, end of processes,
	* modification of filters.
	*
	* EventObjects form a hierarchy similar to the yltk::ExceptionObject allowing
	* to factorize common events in a tree-like structure. Higher detail can
	* be assigned by users by subclassing existing yltk::EventObjects.
	*
	* EventObjects are used by yltk::Command and yltk::Object for implementing the
	* Observer/Subject design pattern. Observers register their interest in 
	* particular kinds of events produced by a specific yltk::Object. This 
	* mechanism decouples classes among them.
	*
	* As opposed to yltk::Exception, yltk::EventObject does not represent error 
	* states, but simply flow of information allowing to trigger actions 
	* as a consequence of changes occurring in state on some yltk::Objects.
	*
	* yltk::EventObject carries information in its own type, it relies on the 
	* appropiate use of the RTTI (Run Time Type Information).
	*
	* A set of standard EventObjects is defined near the end of yltkEventObject.h.
	*
	* \sa yltk::Command
	* \sa yltk::ExceptionObject
	*
	* \ingroup YLTKSystemObjects 
	*/
	class EventObject{
	public:
		/** Constructor and copy constructor.  Note that these functions will be
		* called when children are instantiated. */
		EventObject() {}

		EventObject(const EventObject&){};

		/** Virtual destructor needed  */
		virtual ~EventObject() {}

		/**  Create an Event of this type This method work as a Factory for
		*  creating events of each particular type. */
		virtual EventObject* MakeObject() const=0;  

		/** Print Event information.  This method can be overridden by
		* specific Event subtypes.  The default is to print out the type of
		* the event. */
		virtual void Print(std::ostream& os) const;

		/** Return the StringName associated with the event. */
		virtual const char * GetEventName(void) const=0;

		/** Check if given event matches or derives from this event. */
		virtual bool CheckEvent(const EventObject*) const=0;

	protected:
		/** Methods invoked by Print() to print information about the object
		* including superclasses. Typically not called by the user (use Print()
		* instead) but used in the hierarchical print process to combine the
		* output of several classes.  */
		virtual void PrintSelf(std::ostream& os, Indent indent) const;
		virtual void PrintHeader(std::ostream& os, Indent indent) const;
		virtual void PrintTrailer(std::ostream& os, Indent indent) const;
	private:
		typedef  EventObject * EventFactoryFunction();
		void operator=(const EventObject&);
	};

	/** Generic inserter operator for EventObject and its subclasses. */
	inline std::ostream& operator<<(std::ostream& os, EventObject &e)
	{
		(&e)->Print(os);
		return os;
	}

	/**
	*  Macro for creating new Events
	*/
#define yltkEventMacro( classname , super ) \
	/** \class classname */  \
	class  classname : public super { \
	public: \
		typedef classname    Self; \
		typedef super        Superclass; \
		classname() {} \
		virtual ~classname() {} \
		virtual const char * GetEventName() const { return #classname; } \
		virtual bool CheckEvent(const ::yltk::EventObject* e) const \
		{ return dynamic_cast<const Self*>(e) != NULL ; } \
		virtual ::yltk::EventObject* MakeObject() const \
		{ return new Self; } \
		classname(const Self&s) :super(s){}; \
	private: \
		void operator=(const Self&); \
	};


	/**
	*      Define some common YLTK events
	*/
	yltkEventMacro( NoEvent            , EventObject )
	yltkEventMacro( AnyEvent           , EventObject )
	yltkEventMacro( DeleteEvent        , AnyEvent )
	yltkEventMacro( StartEvent         , AnyEvent )
	yltkEventMacro( EndEvent           , AnyEvent )
	yltkEventMacro( ProgressEvent      , AnyEvent )
	yltkEventMacro( ExitEvent          , AnyEvent )
	yltkEventMacro( AbortEvent         , AnyEvent )
	yltkEventMacro( ModifiedEvent      , AnyEvent )
	yltkEventMacro( InitializeEvent     , AnyEvent )
	yltkEventMacro( IterationEvent     , AnyEvent )
	yltkEventMacro( PickEvent          , AnyEvent )
	yltkEventMacro( StartPickEvent     , PickEvent   )
	yltkEventMacro( EndPickEvent       , PickEvent   )
	yltkEventMacro( AbortCheckEvent    , PickEvent   )
	yltkEventMacro( FunctionEvaluationIterationEvent, IterationEvent )
	yltkEventMacro( GradientEvaluationIterationEvent, IterationEvent )
	yltkEventMacro( FunctionAndGradientEvaluationIterationEvent, IterationEvent )

	yltkEventMacro( UserEvent          , AnyEvent )


}

#endif